#include "Ball.h"
#include "Catapult.h"
#include "Factory.h"
#include "ReportError.h"
#include "BulletCollision/CollisionDispatch/btGhostObject.h"
#include "TextureManager.h"

#include "PlayState.h"
#include "GLCuboid.h"
#include "RadDegConvert.h"
#include "StringUtil.h"
#include <math.h>
#include "SoundManager.h"
#include <assert.h>
#include <gl\glut.h>



Ball::Ball() 
{
	TheEventPoller::Instance()->AddHandler(this);
	m_pos = Vec3f(0, -25, 0);
	//m_isCurrent = false;
	m_mat.SetIdentity();
}

Ball::Ball(const std::string& tex, float radius, float mass, float damping)
{
	m_texPath = tex;
	m_radius = radius;
	CreateCollisionShape(new btSphereShape(btScalar(radius)), mass);
	mp_rigidBody->setDamping(damping, damping);
	int i = TheGame::Instance()->GetGameObjects()->size();
	TheGame::Instance()->AddGameObject(i, this);
	//ResetPosition();
}


bool Ball::Load(File* const f)
{
	//Format is:
	//Texture path
	//radius
	//mass
	//Icon texture(for HUD)
	if(!f->GetString(&m_texPath))
	{
		ReportError("Ball texture not found");
		assert(0);
	}

	if(!f->GetFloat(&m_radius))
	{
		ReportError("BallRadius"+__LINE__);
		assert(0);
	}

	if(!f->GetFloat(&m_mass))
	{
		ReportError("BallMass"+__LINE__);
		assert(0);
	}
	float damping;
	if(!f->GetFloat(&damping))
	{
		ReportError("Can't find ball dampening factor");
		assert(0);
	}
	CreateCollisionShape(new btSphereShape(btScalar(m_radius)), m_mass, COL_BALL, ballCollidesWith);
	mp_rigidBody->setDamping(damping, damping);
	mp_rigidBody->setFriction(0.5f);

	ThePlayState::Instance()->SetBall(this);

	mp_rigidBody->setCcdMotionThreshold(1);
	mp_rigidBody->setCcdSweptSphereRadius(m_radius);
	//ResetPosition();

	return true;
}

const char* Ball::GetTypeName()
{
	return "Ball";
}

GameObject* CreateBall()
{
	return new Ball;
}

void Ball::Draw()
{
	//if(m_isCurrent)
	//{
		glMatrixMode(GL_MODELVIEW);
		glPushMatrix();

			btTransform btTrans;
			
			mp_motionState->getWorldTransform(btTrans);
			btTrans.getOpenGLMatrix(m_mat.m_matrix);
			m_mat.MultiOpenGL();

			Texture* t = TheTextureManager::Instance()->GetTexture(m_texPath);
			t->EnableSphereMap();
			t->Draw();

			glPushMatrix();

			//float ang = mp_rigidBody->getOrientation().getAngle();
			//
			//float x =mp_rigidBody->getOrientation().getAxis().x();
			//float y =mp_rigidBody->getOrientation().getAxis().y();
			//float z =mp_rigidBody->getOrientation().getAxis().z();
			//glRotatef(ang, x,y,z);
			float mcolor[] = { 0.8f, 0.8f, 0.8f, 0.2f };
			glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, mcolor);

			glutSolidSphere(m_radius,16,16);

			glPopMatrix();
			t->DisableSphereMap();
			
		glPopMatrix();
	//}
}

float Ball::GetRadius()
{
	return m_radius;
}

void Ball::ResetPosition()
{
		Catapult* cata = ThePlayState::Instance()->GetCatapultAddress();

		if(!cata->GetIsWaiting())
		{
			btVector3 pos = cata->GetRigidBody()->getWorldTransform().getOrigin();
			btTransform bt;
			bt.setIdentity();

			float hypo = 50;

			float yRot = cata->GetYRotation();

			float ballX = hypo * sin(DegToRad(yRot));
			float ballZ = hypo * cos(DegToRad(yRot));

			btVector3 ballPos(pos.x() + ballX, pos.y() + 21.f, pos.z() + ballZ + 9.7f);

			//std::cout << "yRotation: " + ToString(yRot) + ".\n ball pos: x: " + ToString(ballPos.x()) + " z:" + ToString(ballPos.z()) + "\n";

			bt.setOrigin(ballPos);
			mp_rigidBody->setWorldTransform(bt);
			mp_rigidBody->setLinearVelocity(btVector3(0,0,0));
			cata->MakeAiming();
		}
}

void Ball::Update()
{
	mp_rigidBody->activate(true);
	Catapult* cata = ThePlayState::Instance()->GetCatapultAddress();
	if( cata->GetHasFired() || cata->GetIsWaiting())
	{
		if(!m_onGround)
		{
			mp_rigidBody->setFriction(0.4f);
			mp_rigidBody->setDamping(0.05f,0.05f);
		}
	}
	if(cata->GetIsWaiting() && !cata->GetHasFired())
	{
		float linVelLen = mp_rigidBody->getLinearVelocity().length2();
		float angVelLen = mp_rigidBody->getAngularVelocity().length2();
		if( linVelLen < 0.2f && angVelLen < 0.2f)
		{
			ThePlayState::Instance()->BallThrown();
			ResetPosition();
		}
	}
	if(cata->GetIsAiming())
	{
		mp_rigidBody->setFriction( 1.f);
		mp_rigidBody->setDamping( 0.8f,0.8f);
	}

}

void Ball::OnKeyboardEvent(const SDL_KeyboardEvent& k)
{
	if(k.keysym.sym == SDLK_r && k.state == SDL_PRESSED)
	{
		ResetPosition();
	}
}


void Ball::BTCollided(GameObject* go, const btVector3& ang, const btVector3& lin)
{
	if(go->GetTypeName() == "TargetDummy")
	{
		if(ang.length2() > 0.3f || lin.length() > 0.2f)
		{
			//Do stuff!
			//Score pop up

			//Add score

			static float sco = 0;
			sco += 0.1f;
			if(sco > 1)
			{
				ThePlayState::Instance()->AddToScore(1);
				sco = 0;
			}
			
		}
		if(ang.length2() > 0.5f)
		{
			TheSoundManager::Instance()->SoundEffectPlay(1);
		}
	}
	if(go->GetTypeName() == "Terrain")
	{
		m_onGround = true;
		mp_rigidBody->setFriction(1);
		//mp_rigidBody->setDamping(1, 1);
	}
	else
	{
		m_onGround = false;
	}
}

Ball::~Ball()
{
	TheEventPoller::Instance()->RemoveHandler(this);
	delete mp_rigidBody;
	delete mp_motionState;
}


static bool b = TheGameObjectFactory::Instance()->AddToMap("Ball", CreateBall);